load(
    ":build_defs.bzl",
    "COMMON_COPTS",
    "DEBUGINFO_GRAMMAR_JSON_FILE",
    "CLDEBUGINFO100_GRAMMAR_JSON_FILE",
    "TEST_COPTS",
    "base_test",
    "generate_core_tables",
    "generate_enum_string_mapping",
    "generate_extinst_lang_headers",
    "generate_glsl_tables",
    "generate_opencl_tables",
    "generate_vendor_tables",
    "link_test",
    "opt_test",
    "reduce_test",
    "util_test",
    "val_test",
)

package(
    default_visibility = ["//visibility:private"],
)

licenses(["notice"])

exports_files([
    "CHANGES",
    "LICENSE",
])

py_binary(
    name = "generate_grammar_tables",
    srcs = ["utils/generate_grammar_tables.py"],
)

py_binary(
    name = "generate_language_headers",
    srcs = ["utils/generate_language_headers.py"],
)

generate_core_tables("unified1")

generate_enum_string_mapping("unified1")

generate_opencl_tables("unified1")

generate_glsl_tables("unified1")

generate_vendor_tables("spv-amd-shader-explicit-vertex-parameter")

generate_vendor_tables("spv-amd-shader-trinary-minmax")

generate_vendor_tables("spv-amd-gcn-shader")

generate_vendor_tables("spv-amd-shader-ballot")

generate_vendor_tables("debuginfo")

generate_vendor_tables("opencl.debuginfo.100", "CLDEBUG100_")

generate_extinst_lang_headers("DebugInfo", DEBUGINFO_GRAMMAR_JSON_FILE)

generate_extinst_lang_headers("OpenCLDebugInfo100", CLDEBUGINFO100_GRAMMAR_JSON_FILE)

py_binary(
    name = "generate_registry_tables",
    srcs = ["utils/generate_registry_tables.py"],
)

genrule(
    name = "gen_registry_tables",
    srcs = ["@spirv_headers//:spirv_xml_registry"],
    outs = ["generators.inc"],
    cmd = "$(location generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)",
    tools = [":generate_registry_tables"],
)

py_binary(
    name = "update_build_version",
    srcs = ["utils/update_build_version.py"],
)

genrule(
    name = "gen_build_version",
    srcs = ["CHANGES"],
    outs = ["build-version.inc"],
    cmd = "SOURCE_DATE_EPOCH=0 $(location update_build_version) $$(dirname $(location CHANGES)) $(location build-version.inc)",
    tools = [":update_build_version"],
)

# Libraries

cc_library(
    name = "generated_headers",
    hdrs = [
        ":gen_build_version",
        ":gen_core_tables_unified1",
        ":gen_enum_string_mapping",
        ":gen_extinst_lang_headers_DebugInfo",
        ":gen_extinst_lang_headers_OpenCLDebugInfo100",
        ":gen_glsl_tables_unified1",
        ":gen_opencl_tables_unified1",
        ":gen_registry_tables",
        ":gen_vendor_tables_debuginfo",
        ":gen_vendor_tables_opencl_debuginfo_100",
        ":gen_vendor_tables_spv_amd_gcn_shader",
        ":gen_vendor_tables_spv_amd_shader_ballot",
        ":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter",
        ":gen_vendor_tables_spv_amd_shader_trinary_minmax",
    ],
    copts = COMMON_COPTS,
)

cc_library(
    name = "spirv_tools_headers",
    hdrs = glob([
        "include/spirv-tools/libspirv.h",
        "include/spirv-tools/libspirv.hpp",
        "source/*.h",
        "source/util/*.h",
        "source/val/*.h",
    ]),
    copts = COMMON_COPTS,
    includes = ["source"],
    deps = [
        "@spirv_headers//:spirv_c_headers",
    ],
)

cc_library(
    name = "spirv_tools",
    srcs = glob([
        "source/*.cpp",
        "source/util/*.cpp",
        "source/val/*.cpp",
    ]),
    hdrs = [
        "include/spirv-tools/libspirv.h",
        "include/spirv-tools/libspirv.hpp",
    ],
    copts = COMMON_COPTS + select({
        "@bazel_tools//src/conditions:windows": [""],
        "//conditions:default": ["-Wno-implicit-fallthrough"],
    }),
    includes = ["include"],
    linkstatic = 1,
    visibility = ["//visibility:public"],
    deps = [
        ":generated_headers",
        ":spirv_tools_headers",
        "@spirv_headers//:spirv_c_headers",
        "@spirv_headers//:spirv_common_headers",
    ],
)

cc_library(
    name = "spirv_tools_comp",
    srcs = glob([
        "source/comp/*.cpp",
        "source/comp/*.h",
    ]),
    copts = COMMON_COPTS,
    linkstatic = 1,
    visibility = ["//visibility:public"],
    deps = [
        ":generated_headers",
        ":spirv_tools",
        ":spirv_tools_headers",
        "@spirv_headers//:spirv_common_headers",
    ],
)

cc_library(
    name = "spirv_tools_opt_headers",
    hdrs = glob(["source/opt/*.h"]),
    copts = COMMON_COPTS,
)

cc_library(
    name = "spirv_tools_opt",
    srcs = glob(["source/opt/*.cpp"]),
    hdrs = [
        "include/spirv-tools/instrument.hpp",
        "include/spirv-tools/optimizer.hpp",
    ],
    copts = COMMON_COPTS,
    includes = ["include"],
    linkstatic = 1,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
        ":spirv_tools_headers",
        ":spirv_tools_opt_headers",
        "@spirv_headers//:spirv_common_headers",
    ],
)

cc_library(
    name = "spirv_tools_reduce",
    srcs = glob(["source/reduce/*.cpp"]),
    hdrs = glob(["source/reduce/*.h"]),
    copts = COMMON_COPTS,
    linkstatic = 1,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
        ":spirv_tools_opt",
    ],
)

cc_library(
    name = "spirv_tools_link",
    srcs = glob(["source/link/*.cpp"]),
    hdrs = ["include/spirv-tools/linker.hpp"],
    copts = COMMON_COPTS,
    linkstatic = 1,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
        ":spirv_tools_opt",
    ],
)

cc_library(
    name = "tools_util",
    srcs = glob(["tools/util/*.cpp"]),
    hdrs = glob(["tools/util/*.h"]),
    copts = COMMON_COPTS,
    linkstatic = 1,
    visibility = ["//visibility:public"],
    deps = [":spirv_tools"],
)

# Tools

cc_binary(
    name = "spirv-as",
    srcs = [
        "tools/as/as.cpp",
        "tools/io.h",
    ],
    copts = COMMON_COPTS,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
    ],
)

cc_binary(
    name = "spirv-dis",
    srcs = [
        "tools/dis/dis.cpp",
        "tools/io.h",
    ],
    copts = COMMON_COPTS,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
    ],
)

cc_binary(
    name = "spirv-val",
    srcs = [
        "tools/io.h",
        "tools/val/val.cpp",
    ],
    copts = COMMON_COPTS,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
        ":tools_util",
    ],
)

cc_binary(
    name = "spirv-opt",
    srcs = [
        "tools/io.h",
        "tools/opt/opt.cpp",
    ],
    copts = COMMON_COPTS,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
        ":spirv_tools_opt",
        ":tools_util",
    ],
)

cc_binary(
    name = "spirv-reduce",
    srcs = [
        "tools/io.h",
        "tools/reduce/reduce.cpp",
    ],
    copts = COMMON_COPTS,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
        ":spirv_tools_opt",
        ":spirv_tools_reduce",
        ":tools_util",
    ],
)

cc_binary(
    name = "spirv-link",
    srcs = [
        "tools/io.h",
        "tools/link/linker.cpp",
    ],
    copts = COMMON_COPTS,
    visibility = ["//visibility:public"],
    deps = [
        ":spirv_tools",
        ":spirv_tools_link",
    ],
)

cc_binary(
    name = "spirv-cfg",
    srcs = [
        "tools/cfg/bin_to_dot.cpp",
        "tools/cfg/bin_to_dot.h",
        "tools/cfg/cfg.cpp",
        "tools/io.h",
    ],
    copts = COMMON_COPTS,
    visibility = ["//visibility:public"],
    deps = [":spirv_tools"],
)

# Unit tests

cc_library(
    name = "test_common",
    testonly = 1,
    srcs = [
        "test/test_fixture.h",
        "test/unit_spirv.cpp",
        "test/unit_spirv.h",
    ],
    compatible_with = [],
    copts = TEST_COPTS,
    includes = ["test"],
    linkstatic = 1,
    deps = [
        ":spirv_tools",
        "@com_google_googletest//:gtest",
    ],
)

cc_library(
    name = "link_test_common",
    testonly = 1,
    srcs = ["test/link/linker_fixture.h"],
    compatible_with = [],
    copts = TEST_COPTS,
    linkstatic = 1,
    deps = [
        ":spirv_tools_link",
        ":test_common",
    ],
)

cc_library(
    name = "opt_test_common",
    testonly = 1,
    srcs = ["test/opt/pass_utils.cpp"],
    hdrs = [
        "test/opt/assembly_builder.h",
        "test/opt/function_utils.h",
        "test/opt/module_utils.h",
        "test/opt/pass_fixture.h",
        "test/opt/pass_utils.h",
    ],
    compatible_with = [],
    copts = TEST_COPTS,
    linkstatic = 1,
    deps = [
        ":spirv_tools_opt",
        ":test_common",
    ],
)

cc_library(
    name = "reduce_test_common",
    testonly = 1,
    srcs = [
        "test/reduce/reduce_test_util.cpp",
        "tools/io.h",
    ],
    hdrs = ["test/reduce/reduce_test_util.h"],
    compatible_with = [],
    copts = TEST_COPTS,
    linkstatic = 1,
    deps = [
        ":spirv_tools_reduce",
        ":test_common",
    ],
)

cc_library(
    name = "val_test_common",
    testonly = 1,
    srcs = [
        "test/val/val_code_generator.cpp",
        "test/val/val_fixtures.h",
    ],
    hdrs = [
        "test/val/val_code_generator.h",
    ],
    compatible_with = [],
    copts = TEST_COPTS,
    linkstatic = 1,
    deps = [":test_common"],
)

# PCH (precompiled header) tests only work when using CMake and MSVC on Windows,
# so they will be skipped in the Bazel builds.

[base_test(
    name = f[5:-4],  # strip test/, .cpp
    srcs = [f],
) for f in glob(
    ["test/*.cpp"],
    exclude = [
        "test/cpp_interface_test.cpp", # has its own base_test below.
        "test/log_test.cpp", # has its own base_test below.
        "test/pch_test.cpp", # pch tests are skipped.
        "test/timer_test.cpp", # has its own base_test below.
    ],
)]

# This test uses unistd.h and does not run on Windows.
base_test(
    name = "timer_test",
    srcs = select({
        "@bazel_tools//src/conditions:windows": [],
        "//conditions:default": ["test/timer_test.cpp"],
    }),
)

base_test(
    name = "cpp_interface_test",
    srcs = ["test/cpp_interface_test.cpp"],
    deps = [":spirv_tools_opt"],
)

base_test(
    name = "log_test",
    srcs = ["test/log_test.cpp"],
    deps = [":spirv_tools_opt"],
)

[link_test(
    name = f[10:-4],  # strip test/link/, .cpp
    srcs = [f],
) for f in glob(
    ["test/link/*.cpp"],
)]

[opt_test(
    name = f[9:-4],  # strip test/opt/, .cpp
    srcs = [f],
) for f in glob(
    ["test/opt/*.cpp"],
    # pch tests are skipped.
    exclude = ["test/opt/pch_test_opt.cpp"],
)]

[opt_test(
    name = "dom_tree_" + f[24:-4],  # strip test/opt/dominator_tree/, .cpp
    srcs = [f],
) for f in glob(
    ["test/opt/dominator_tree/*.cpp"],
    # pch tests are skipped.
    exclude = ["test/opt/dominator_tree/pch_test_opt_dom.cpp"],
)]

[opt_test(
    name = "loop_" + f[28:-4],  # strip test/opt/loop_optimizations/, .cpp
    srcs = [f],
) for f in glob(
    ["test/opt/loop_optimizations/*.cpp"],
    # pch tests are skipped.
    exclude = ["test/opt/loop_optimizations/pch_test_opt_loop.cpp"],
)]

[reduce_test(
    name = f[12:-4],  # strip test/reduce/, .cpp
    srcs = [f],
) for f in glob(["test/reduce/*.cpp"])]

[util_test(
    name = f[10:-4],  # strip test/util/, .cpp
    srcs = [f],
) for f in glob(["test/util/*.cpp"])]

[val_test(
    name = f[9:-4],  # strip test/val/, .cpp
    srcs = [f],
) for f in glob(
    ["test/val/*.cpp"],
    exclude = [
        "test/val/pch_test_val.cpp", # pch tests are skipped.
    ],
)]

